home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / compress / tar321__.zip / SOURCES.ZIP / TAR.C < prev    next >
Text File  |  1997-03-31  |  32KB  |  946 lines

  1. /* tar.c - Tape ARchive utility program (main function)
  2.  * Author: T.V.Shaporev
  3.  * Creation date: 14 Dec 1990
  4.  *
  5.  * The program works in a same fashion under UNIX (most clones) and
  6.  * MS-DOS. The main idear was to develop a tool for file transferring
  7.  * via diskette between different operating systems - such as all UNIX
  8.  * clones, MS-DOS, RSX, VAX/VMS - and all others which support tar
  9.  * format on a diskette.
  10.  * First step on this way (made in 1989) lies in adapting common UNIX
  11.  * tar program to MS-DOS.
  12.  *
  13.  * On the second step
  14.  *  - some bugs were fixed (especially in DOS-applied codes) and some
  15.  *    optimization were done;
  16.  *  - nonstandard (under DOS) diskette formats were added (i.e.
  17.  *    DEC Rainbow and 80 tracks & 9 sectors format)
  18.  *  - the possibility for compress encoding were included
  19.  *    (this compressor has the best ratio among all others which
  20.  *    I know, but don't ask me about its speed). Compressed-file
  21.  *    format is compatible with the common versions of tar, so You
  22.  *    can extract the compressed image from the archive by the
  23.  *    common program, but I doubt You could uncompress them at last.
  24.  *
  25.  * On the fird step the program was totally (newly) overwritten to bypass
  26.  * any copyright exclamations. In fact, it must be considered new program
  27.  * but I prefer to continue version enumeration (I hope, nobody cares).
  28.  *
  29.  * I think, this program must be called Tar (with capital first letter)
  30.  * to distinguish it from regular UNIX tar.
  31.  *
  32.  * The program's behaviour is analogous to usual tar, and I hope, its
  33.  * internal help will be enough to understand the differences.
  34.  *
  35.  * The program doesn't perform any text file conversion - it passes
  36.  * strict binary image of each file. If You has a problems with reading
  37.  * DOS text files under UNIX (or UNIX files under DOS) please use my
  38.  * dostext program.
  39.  *
  40.  * The program must be compiled by Turbo C 2.0 compiler (in a compact
  41.  * model) under MS-DOS. Please don't replace dynamic arrays back to
  42.  * static and automatic - MS-DOS compilers dislike them.
  43.  *
  44.  *            tim    tim@ecsc.mipt.su    14 Dec 1990
  45.  */
  46. /* Version 3.01
  47.  * Handling of the 'l' option corrected
  48.  */
  49. /* Version 3.02                                       31 Dec 1990
  50.  *  - great deal of minor corrections
  51.  *  - u<pdate> option expanded to extracting
  52.  *  - j<ournal> option added (comment storying files)
  53.  *  - wildcards * and ? are now processed in archive; this may be
  54.  *    suppressed by s<trict> option
  55.  *  - d<elete> option added to replace previous occurencies of files
  56.  *    in archive on storying, or deleting files from archive when
  57.  *    whithout a<dd> parameter - this is for file archives only!
  58.  */
  59. /* Version 3.03                                       22 Feb 1991
  60.  *  - an error corrected in mismatch() (file extract.c)
  61.  *  - decreased stack requirements for tree processing
  62.  *    (see store() in store.c and putfiles() in tar.c)
  63.  *  - added codes to prevent archive file self-storying
  64.  *    (not quite reliable for MS-DOS)
  65.  *  - bincall() invocations changed by calls to rmdir() and mkdir()
  66.  *    this is done automatically for 386/ix and may be switched by
  67.  *    RMKDIR macro
  68.  */
  69. /* Version 3.04                                       29 Jul 1991
  70.  *  - a direct intialization of static global variables inserted into
  71.  *    lzencode() and lzdecode() - see file lzpack.c
  72.  */
  73. /* Version 3.04b                                      03 Oct 1991
  74.  *  - a minor correction of bincall()
  75.  *  - added default block number = sectors on track (MS-DOS)
  76.  */
  77. /* Version 3.05                                       11 Nov 1991
  78.  *  - block factor for diskette writing is set to 1 for most BIOS
  79.  *    compatibility
  80.  *  - scantape() is slightly optimized
  81.  */
  82. /* Version 3.06                                       17 Dec 1991
  83.  *  - n<onest> option applied to all actions (see inarg() in extract.c)
  84.  *  - command-line-extension-file option (responce file) added
  85.  *    for vak (vak@kiae.su) request (see append() in tar.c)
  86.  *  - p<ermission> option added to save directories permissions (UNIX)
  87.  */
  88. /* Version 3.06b                                      22 Dec 1991
  89.  *   - UNIX to DOS renaming algorithm (dot elimination) slightly
  90.  *     changed (see extract.c)
  91.  *   - most of output redirected to stdout (vs stderr)
  92.  */
  93. /* Version 3.07                                       28 Dec 1992
  94.  *   - all unary apostrofs in string constants preserved by backslashes
  95.  *   - reading file list from stdin allowed (see append() in tar.c)
  96.  *   - input redirected to /dev/tty under UNIX
  97.  *   - support for traditional UNIX compression algorithm
  98.  *   - few changes in converting UNIX names for DOS
  99.  */
  100. /* Version 3.07b                                      20 Jan 1993
  101.  *   - gethead() does not return FALSE while errors,
  102.  *     scantape() looks for tape reading errors
  103.  */
  104. /* Version 3.08                                       22 Feb 1993
  105.  *   - method-dependent comression indicator masks (see percent.c)
  106.  *   - 'z' option applied to catalog printing (see catalog())
  107.  *   - compatibility corrections in directory structure checking
  108.  *   - st.st_size == codesize - means file unpacked! (see extract.c)
  109.  */
  110. /* Version 3.09                                       14 Mar 1993
  111.  *   - a bug fixed wich prevents archiving unpacked files at all
  112.  *     (ha-ha!) - see store.c
  113.  *   - changed header description to support new features
  114.  *     see define.h
  115.  *   - support for P1003 and GNU file types - 't' option only! -
  116.  *     see extract.c
  117.  *   - small changes in #ifdef-s to distinguish SCO UNIXes from
  118.  *     XENIXes - see store.c
  119.  *   - regular file processing extracted into separate source
  120.  *     files (see savefile.c & restore.c)
  121.  *   - support for devices and FIFOs added
  122.  *   - 'l' option added for DOS (copy linked files)
  123.  *   - support for System V extents - see extract.c and restore.c
  124.  *     to read archives only, extents may not be unpacked on the
  125.  *     fly - alas, that's all for now
  126.  *   - an error corrected in roll.c
  127.  */
  128. /* Version 3.10                                       28 Jun 1993
  129.  *   - a bug fixed in old compression code (see lzpack.c)
  130.  *   - added possibility to run through compress (',' comma option)
  131.  *     see tar.c, tape.c and compress.c
  132.  *   - comments will not be printed unless 'j' is given (extract.c)
  133.  *   - separated compress-related codes
  134.  */
  135. /* Version 3.11                                       14 Jul 1993
  136.  *   - support for QIC-02 streamers (first version!)
  137.  *     devices supported: fastape, everex
  138.  */
  139. /* Version 3.12                                       29 Sen 1993
  140.  *   - slack area in archive is filled by nulls to improve compression
  141.  *   - added support for Wangtek (QIC-02) device
  142.  *   - a bug fixed in memory release ('pk_out' variable - see _done())
  143.  *   - program support for QIC-02 drive number and tape format
  144.  *     selection
  145.  *   - experimental (!) support for appending QIC-02 tapes
  146.  *     (see qback() in qicface.c)
  147.  *   - LZW support splitted into compressor and extractor and
  148.  *     the letter included in official release (see unlzw.c etc.)
  149.  *   - get default file name from TAPE environment variable
  150.  *   - 'o' flag for DOS means prevent file overwriting
  151.  */
  152. /* Version 3.12b                                      10 Nov 1993
  153.  *   - an error corrected in QIC device selection (see qicface.c)
  154.  *   - eliminated idle rewindings around QIC tape initialisation
  155.  */
  156. /* Version 3.13                                       26 Dec 1993
  157.  *   - online inflatter (unzip) and corresponding '.' (dot) option
  158.  */
  159. /* Version 3.14                                       19 Feb 1994
  160.  *   - online deflatter (zip); compilation model changed to large
  161.  */
  162. /* Version 3.15 - general bugfix                      03 Apr 1994
  163.  *   - strerror() missed in some UNIXes, so psyserr() function added
  164.  *     into tape.c
  165.  *   - extended local header signature inserted in deflated output and
  166.  *     unzclose() changed to uderstand both formats
  167.  *     (see zipdefs.h, zippipe.c and diszip.c)
  168.  *   - pkflush() output is aligned to pksize boundary if output is not
  169.  *     regular file or DOS floppy to avoid block device alignment error
  170.  *     (see tape.c)
  171.  *   - "total blocks" number is reported accordingly to real archive
  172.  *     size (see tape.c, extract.c, tar.c)
  173.  */
  174. /* Version 3.15b - bugfix                             15 Jun 1994
  175.  *   - uname() (see restore.c) bug fixed;
  176.  *   - bi_reverse() cleaned (__emit__ed code cause BC 3.1 error)
  177.  *     moved to trees.c and renamed;
  178.  *   - getlg() changed to look for NEEDBITS buffer;
  179.  *   - diszip.c cleaned a bit.
  180.  */
  181. /* Version 3.16                                       ?? Jul 1994
  182.  *   - got rid of __emit__() - completely;
  183.  *   - got rid of "#pragma pack()" - see define.h;
  184.  *   - error corrected in ct_free() (see trees.c);
  185.  *   - default (-e) compression changed to deflation,
  186.  *     keep support for old-style decompression;
  187.  *   - exclude file(s) specification ('#' option) - up to 16 patterns
  188.  *     (see fmatch.c, store.c, extract.c);
  189.  *   - autodetection of compressed or (g)zipped archives
  190.  *     (pktest() from extract.c etc.)
  191.  */
  192. /* Version 3.17                                       04 Nov 1994
  193.  *   - changed foloppy calibrating logic (see disk.c), added diskspec()
  194.  *     function (see pclevel.asm) and support for 2.88M floppies (?);
  195.  *   - corrected missing IBEGIN updating into diszip.c;
  196.  *   - added 'drop online' op. into streamer() and qend();
  197.  *   - restored handling of ':' option in savefile();
  198.  *   - restored "idle rewindings" while starting tape since
  199.  *     they arrear to improve reliability;
  200.  *   - use conditional XOFF flag in ct_iobyte() (see streamer.c);
  201.  *   - added explicit call to tzset() in tar.c;
  202.  *   - implemented 'add' and 'skip' device parameters;
  203.  *   - unzipping stored file (see diszip.c),
  204.  *     gmtime() changed to localtime() in zippipe.c;
  205.  *   - GNU-like command line syntax, environment configuration;
  206.  *   - cascade EOI changed to specific in cthandle.asm.
  207.  */
  208. /* Version 3.18                                       24 Dec 1994
  209.      - ASPI support (first version!);
  210.      - bug fixed in blocksize reading (see readblk() in readopt.c);
  211.      - bug fixed in pattern comparing (see mismatch() in fmatch.c)
  212.  */
  213. /* Version 3.20g                                       03 Jul 1996
  214.      - fix for 'file changed size'
  215.      - attempt to handle EOF inside zip
  216.  */
  217. /* Version 3.21                                        30 Mar 1997
  218.      - support for Win95 long file names
  219.      - incorporated ASPI fixes and progress indicator from
  220.        Nelson Bolyard <nelson@bolyard.ix.netcom.com>
  221.      - added GF_MUL processing in extract() (bugfix)
  222.      - 'optlist' data structure in readopt.c changed to more portable
  223. */
  224. #include "sysup.h"
  225. #include "modern.h"
  226. #include "zippipe.h"
  227. #include "lzwbits.h"
  228. #include "lzwhead.h"
  229. #include "compress.h"
  230.  
  231. static char note[] = "\n\
  232.    Tape ARchive utility      v3.21 beta      (C) 1990-97 Tim V.Shaporev\n";
  233.  
  234. #ifdef UNIX
  235. static char help[] = "\n\
  236.    Usage: tar -<options> [tapefile] [blocksize] [disksize] file ...\n\n\
  237.    Options are:                       s - no wildcards for archive\n\
  238.      c - put files to new archive     i - ignore read errors\n\
  239.      a,r - add files to archive       m - forget files origin date/time\n\
  240.      y - move files to archive        o - forget files owner\n\
  241.      x - extract files from archive   l - type missed links\n\
  242.      t - show archive catalog         p - save directories & permissions\n\
  243.      d - delete files in archive      n - no proceed with dir nesting\n\
  244.      u - update files                 / - omit left \'/\' in file names\n\
  245.      v - verbose                      0...7 - number of tape device\n\
  246.      w - acknowledge operations       j - comment storying files\n\
  247.      e - compress encode files        f - next arg is an archive file\n\
  248.      z - old-fashion compression      b - next arg is a blocking factor\n\
  249.      , - run through compressor       @ - next arg is a responce file\n\
  250.      . - run through (g)zip           # - exclude file(s) specification\n\
  251. ";
  252. #endif
  253.  
  254. #ifdef MSDOS
  255. static char help[] = "\n\
  256.    Usage: tar -<options> [tapefile] [blocksize] [disksize] file ...\n\n\
  257.    Options are:\n\
  258.      c - put files to new archive     s - no wildcards for archive\n\
  259.      a,r - add files to archive       m - forget files date/time\n\
  260.      y - move files to archive        n - no proceed with dir nesting\n\
  261.      x - extract files from archive   l - copy linked files\n\
  262.      t - show archive catalog         o - prevent files overwriting\n\
  263.      d - delete files in archive      \\ - omit left \'\\\' in file names\n\
  264.      u - update files                 : - omit DOS drive name\n\
  265.      v - verbose                      0...3 - number of storage device\n\
  266.      w - acknowledge operations       j - comment storying files\n\
  267.      i - ignore read errors           f - next arg is an archive file\n\
  268.      e - compress encode files        b - next arg is a blocking factor\n\
  269.      z - old-fashion compression      k - next arg is K diskette size\n\
  270.      , - run through compressor       @ - next arg is a responce file\n\
  271.      . - run through (g)zip           # - exclude file(s) specification\n\
  272. \n\
  273.    Most of options may be combined. Wildcards * and ? are o\'k\n\
  274. ";
  275. static char devlist[] = "\n\
  276.    The following \"file names\" will be treated as diskette format/size:\n\
  277. \tfd048ss8  - 160K\tfd048ds8  - 320K\tfd135ds9  - 720K\n\
  278. \tfd048ss9  - 180K\tfd048ds9  - 360K\tfd135ds18 - 1.4M\n\
  279. \tfd096ds9  - 720K\tfd096ds15 - 1.2M\trainbow\n\
  280. \n\
  281.    Streamer \"file name\" syntax (full form) is:\n\
  282. \t<device>:base:=<base address>h,dma:=<DRQ>[,irq:=<IRQ>][,norewind]\n\
  283.    Streamer device clones supported are:\n\
  284. \tarchive,\teverex,\t\twangtek\n\
  285. \n\
  286.    The following \"file names\" are aliases for ASPI driven SCSI streamer:\n\
  287. \taspitape,\taspimgr$,\taspi\n\
  288.    Full form is:\n\
  289. \taspi[:target:=<n>[,lun:=<n>][,adapter:=<n>][,density:=<x>]]\n\
  290. ";
  291. #endif
  292.  
  293. #include <signal.h>
  294. #include <stdio.h>
  295. #ifdef MSDOS
  296. #    include <string.h>
  297. #    include <stdlib.h>
  298. #    include <time.h>
  299. #    include <dos.h>
  300. #else
  301.     char *strcpy(), *strcat(), *strncpy();
  302.         char *getenv(), *malloc(), *realloc();
  303.     int  open(), read(), close(), link(), unlink(), isatty();
  304.     int  strlen(), strncmp(), atoi();
  305.         void exit(), free();
  306.     long lseek();
  307. #endif
  308.  
  309. #define __ALLOCEXT__
  310. #include "define.h"
  311.  
  312. #include "lzpack.h"
  313. #include "roll.h"
  314.  
  315. #ifdef UNIX
  316. #    ifdef MAXNAMSIZ
  317. #        define MAXPATH MAXNAMSIZ+1
  318. #    else
  319. #        define MAXPATH 512+1
  320. #    endif
  321. #endif
  322. #ifndef MAXPATH
  323. #    ifdef PATHSIZE
  324. #        define MAXPATH PATHSIZE+1
  325. #    endif
  326. #endif
  327.  
  328. #ifdef UNIX
  329. #    ifndef RMKDIR
  330. int bincall(name, args)
  331. char *name, *args;
  332. {
  333.    extern int fork(), execl(), wait();
  334.    int i; register k;
  335.    char b[24];
  336.  
  337.    if (fork() == 0) {
  338.       (void)execl(strcat(strcpy(b, "/bin/"),     name), name, args, 0);
  339.       (void)execl(strcat(strcpy(b, "/usr/bin/"), name), name, args, 0);
  340.       k = -1;
  341.    } else {
  342.       (void)wait(&i); k = i>>8;
  343.    }
  344.    return k;
  345. }
  346. #    endif
  347. #endif
  348.  
  349. short headsum(h)
  350. header *h;
  351. {
  352.    register short i, j;
  353.  
  354.    for (i=0, j=0; i<BLKSIZE; i++) {
  355.       j += i >= MAXTNAME+3*8+2*12 && i < MAXTNAME+3*8+2*12+8 ?
  356.            ' ' : *((unsigned char *)h + i);
  357.    }
  358. #if ~0 != 0177777
  359.    return j & 0177777;
  360. #else
  361.    return j;
  362. #endif
  363. }
  364.  
  365. node *finditem(fname, prev, head)
  366. char *fname; node **prev, *head;
  367. {
  368.    register node *this;
  369.    register i;
  370.  
  371.    *prev = this = head; i = 1;
  372.    while (this && i>0) {
  373.       if ((i = strcmp(fname, this->name)) > 0) {
  374.          *prev = this; this = this->next;
  375.       }
  376.    }
  377.    return i ? NONE : this;
  378. }
  379.  
  380. node *additem(fname, prev, head)
  381. char *fname; node *prev, **head;
  382. {
  383.    register node *this;
  384.    register i;
  385.  
  386.    i = sizeof(node) - (MINTNAME-1) + strlen(fname);
  387.    if ((this = (node *)malloc(i)) == NULL) return NONE;
  388.    (void)strcpy(this->name, fname);
  389.    this->prev = prev;
  390.    if (prev != NONE) {
  391.       if ((this->next = prev->next) != NONE) this->next->prev = this;
  392.       prev->next = this;
  393.    } else {/* initialise the list */
  394.       this->next = NONE;
  395.       (*head) = this;
  396.    }
  397.    return this;
  398. }
  399.  
  400. void delitem(this, head)
  401. node *this, **head;
  402. {
  403.    if (this == *head) {/* head of the list */
  404.       if (this->next != NONE) {
  405.          this->next->prev = this->prev != this ? this->prev : this->next;
  406.       }
  407.       this = this->next;
  408.       free(*head);
  409.       *head = this;
  410.    } else {
  411.       if (this->next != NONE) this->next->prev = this->prev;
  412.       this->prev->next = this->next;
  413.       free(this);
  414.    }
  415. }
  416.  
  417. static void _done __ARGS__(( void ))
  418. {
  419.    register node *p, *q;
  420. #ifdef MSDOS
  421.    extern void qend __ARGS__((void)), aspiend __ARGS__((void));
  422.  
  423.    if      (devtype == DEV_QIC2) qend();
  424.    else if (devtype == DEV_ASPI) aspiend();
  425.    if (archname) free(archname);
  426. #endif
  427.    if (responce)  free(responce);
  428.    if (argvector) free((char*)argvector);
  429.    if (tarcmd)    free(tarcmd);
  430.    p = timehead; while (p) { q = p->next; free(p); p = q; }
  431. #ifdef UNIX
  432.    p = linkhead; while (p) { q = p->next; free(p); p = q; }
  433. #endif
  434.    if (hwrite >= 0 && hwrite != handle) {
  435.       (void)close(hwrite); (void)unlink(scratch);
  436.    }
  437.    if (io_2nd && io_2nd!=io_buf) free(io_2nd);
  438.    if (io_buf) free(io_buf);
  439.    if (pk_out && pk_out!=pk_inp) free(pk_out);
  440.    if (pk_inp) free(pk_inp);
  441.    zipfree();
  442.    unzfree();
  443. #ifdef USE_COMPRESS
  444.    z_reltab();
  445. #endif
  446.    z_relmem();
  447.    delroll();
  448. }
  449.  
  450. void done(n)
  451. int n;
  452. {
  453. #ifdef MSDOS
  454.    if (startdir) { (void)cwd(startdir); free(startdir); }
  455. #endif
  456.    _done(); exit(n);
  457. }
  458.  
  459. void outmem(f)
  460. FILE *f;
  461. {
  462.    (void)fprintf(f, "Tar: not enough memory\n");
  463.    done(ESMALL);
  464. }
  465.  
  466. char *salloc(n)
  467. int n;
  468. {
  469.    register char *p;
  470.  
  471.    if ((p = malloc(n)) == NULL) outmem(stderr);
  472.    return p;
  473. }
  474.  
  475. int yes_no(d)
  476. char d;
  477. {
  478.    register int c;
  479. #ifdef MSDOS
  480.    extern int getkey __ARGS__((void));
  481.  
  482.    do {
  483.       c = getkey();
  484.    } while (c!='y' && c!='Y' && c!='n' && c!='N' && c!='q' && c!='Q' &&
  485.             c!='\r' && c!='\n' && c!=27 && c!=3);
  486.    if (c == 3) {
  487.       cbreak = TRUE;
  488.    } else if (c >= ' ') {
  489.       (void)fprintf(stderr, "%c", c);
  490.    } else if (d) {
  491.       (void)fprintf(stderr, "%c", d);
  492.    }
  493.    (void)fprintf(stderr, "\n");
  494. #else
  495.    if ((c = getc(myinp)) == '\n') {
  496.       c = d;
  497.    } else {
  498.       while (getc(myinp) != '\n') ;
  499.    }
  500. #endif
  501.    if (c == 'q' || c == 'Q') done(EXIT);
  502.    return c == 'y' || c == 'Y';
  503. }
  504.  
  505. void prmode(c, m)
  506. char c; int m;
  507. {
  508.    (void)fprintf(myout, "%c%c%c%c%c%c%c%c%c%c", c,
  509.       (m & S_IREAD ? 'r' : '-'), (m & S_IWRITE? 'w' : '-'),
  510.       (m & S_ISUID ? 's' : m & S_IEXEC ? 'x' : '-'),
  511.       (m & 00040   ? 'r' : '-'), (m & 00020   ? 'w' : '-'),
  512.       (m & S_ISGID ? 's' : m & 00010   ? 'x' : '-'),
  513.       (m & 00004   ? 'r' : '-'), (m & 00002   ? 'w' : '-'),
  514.       (m & S_ISVTX ? 't' : m & 00001   ? 'x' : '-'));
  515. }
  516.  
  517. int okwork(c, p, s, n)
  518. char c, p, *n;
  519. struct stat *s;
  520. {
  521.    register m;
  522.  
  523.    (void)fprintf(stderr, "%c ", c);
  524.    if (v_flag) {
  525.       if (p == ' ' && (m = s->st_mode & S_IFMT) != 0) {
  526.          switch (m) {
  527.             case S_IFREG: break;
  528.             case S_IFDIR: p = 'd'; break;
  529.             case S_IFIFO: p = 'p'; break;
  530.             case S_IFCHR: p = 'c'; break;
  531.             case S_IFBLK: p = 'b'; break;
  532. #ifdef S_IFLNK
  533.             case S_IFLNK: p = 'l'; break;
  534. #endif
  535.             default:      p = '?';
  536.          }
  537.       }
  538.       prmode(p, (int)(s->st_mode));
  539.       (void)fprintf(stderr," %3d/%1d %7ld ",s->st_uid,s->st_gid,s->st_size);
  540.    }
  541.    (void)fprintf(stderr, "%s : ", n);
  542.    return YES_NO();
  543. }
  544.  
  545. void onintr() { (void)signal(SIGINT,  SIG_IGN); cbreak = TRUE; }
  546. #ifdef UNIX
  547. void onquit() { (void)signal(SIGQUIT, SIG_IGN); cbreak = TRUE; }
  548. void onhup()  { (void)signal(SIGHUP,  SIG_IGN); cbreak = TRUE; }
  549. #endif
  550.  
  551. static void set_sig __ARGS__(( void ))
  552. {
  553.    if (signal(SIGINT, SIG_IGN) != SIG_IGN) (void)signal(SIGINT, onintr);
  554. #ifdef UNIX
  555.    if (signal(SIGHUP, SIG_IGN) != SIG_IGN) (void)signal(SIGHUP, onhup );
  556.    if (signal(SIGQUIT,SIG_IGN) != SIG_IGN) (void)signal(SIGQUIT,onquit);
  557. #endif
  558. }
  559.  
  560. static void delfile __ARGS__(( void ))
  561. {
  562.    if (v_flag)
  563.       (void)fprintf(myout, "d %s, %ld bytes, %ld tape blocks\n",
  564.          hblock->m.name, st.st_size, (st.st_size + (BLKSIZE-1))/BLKSIZE);
  565.    if (usize()) skipfile();
  566. }
  567.  
  568. static void putfiles __ARGS__(( int, char ** ));
  569.  
  570. static void putfiles(argc, argv)
  571. int argc; char *argv[];
  572. {
  573.    char fnmbuf[MAXPATH];
  574.  
  575.    for (; argc>0; --argc, argv++) {
  576.       if (strlen(*argv) > MAXTNAME) {
  577.          (void)fprintf(myout, "Tar: \'%s\' name too long\n", *argv);
  578.          continue;
  579.       }
  580. #ifdef MSDOS
  581.       if (lfn_active & ~1) (void)lchmod(".",0,0);
  582.       {  register c; register char *from = *argv, *to = fnmbuf;
  583.          do {
  584.             if ((c = *from++) == '\\') c = '/'; else
  585.             if ((c>='A' && c<='Z') && !lfn_active) c -= 'z'-'Z';
  586.          } while ('\0' != (*to++ = c));
  587.       }
  588. #else
  589.       (void)strcpy(fnmbuf, *argv);
  590. #endif
  591.       store(fnmbuf);
  592.    }
  593. }
  594.  
  595. static void stdhelp __ARGS__((void))
  596. {
  597. #ifdef MSDOS
  598.    extern int ioctl();
  599. #endif
  600.    (void)fprintf(stdout, note);
  601.    (void)fprintf(stdout, help);
  602.    (void)fflush (stdout);
  603. #ifdef MSDOS
  604.    if (ioctl(fileno(stdout),0) & 0x80) {/* not a disk file */
  605.       (void)fprintf(stderr,"\nDo you want to see device list? ");
  606.       (void)fflush (stderr);
  607.       if (!YES_NO()) return;
  608.    }
  609.    (void)fprintf(stdout, devlist);
  610. #endif
  611. }
  612.  
  613. int pkalloc()
  614. {
  615.    register k = FALSE;
  616.  
  617.    if (pktype == PKpLZW || pktype == PKZIP) {/* Pipe compression */
  618.       pksize = BLKSIZE;
  619.       if (d_flag || x_flag || t_flag) {
  620.          if (NULL == (pk_inp=malloc(pksize))) k = TRUE;
  621.       }
  622.       if (!k && (d_flag || a_flag)) {
  623.          if (NULL == (pk_out=malloc(pksize))) {
  624.             if (pk_inp) { free(pk_inp); pk_inp = NULL; }
  625.             k = TRUE;
  626.          }
  627.       }
  628.    } else {/* Individual file(s) compression */
  629.       pksize = PKSIZE;
  630.       if (d_flag || x_flag || (t_flag && pktype == PKfLZW)) {
  631.          if (NULL == (pk_out=malloc(pksize))) k = TRUE;
  632.       }
  633.       if (!k && (d_flag || a_flag)) {
  634.          if (NULL == (pk_inp=malloc(pksize))) {
  635.             if (pk_out) { free(pk_out); pk_out = NULL; }
  636.             k = TRUE;
  637.          }
  638.       }
  639.    }
  640.    return k;
  641. }
  642.  
  643. #ifdef MSDOS
  644. static int getfulldir(drv, dest)
  645. int drv; char *dest;
  646. {
  647.    if (lgetcurdir(drv+1, dest+3)) {
  648.       (void)fprintf(myout,
  649.          "Tar: warning: can\'t get current dir on %c:\n", drv+'A');
  650.       return -1;
  651.    }
  652.    dest[0] = (char)(drv+'A'); dest[1] = ':'; dest[2] = '\\';
  653.    return 0;
  654. }
  655. #endif
  656.  
  657. int main(argc, argv)
  658. int argc; char *argv[];
  659. {
  660.    register i, k;
  661.    int cenv; char **earg;
  662.  
  663.    if (argc < 2) {
  664.       stdhelp(); return ERRARG;
  665.    }
  666. #ifdef MSDOS
  667.    setdrive = FALSE;
  668.    filemask = FA_SYSTEM+FA_HIDDEN+FA_RDONLY+FA_DIREC+FA_ARCH;
  669. #endif
  670.    pktype = PKNONE;
  671.    pklock = FALSE;
  672.    cblock = 0;
  673.    tapename = NULL;
  674.    myout = stdout;
  675.    xcnt = 0;
  676.    lzwbits = BITS; ziplevel = 6;
  677.  
  678.    /* Skip the program name */ --argc; ++argv;
  679.    appname = NULL;
  680.    if ((cenv = envbuild(0, &earg)) > 0) {
  681.       i = readopt(&cenv, &earg, OPTFLAG);
  682.       if (i < cenv) {
  683.          revector(argc, &argv, cenv-i);
  684.          /* append new arguments */
  685.          while(i<cenv) argv[argc++] = earg[i++];
  686.       }
  687.       if (appname) argc = argfile(argc, &argv, appname, &responce);
  688.    }
  689.    i = readopt(&argc, &argv, 0);
  690.    pktype &= OPTMASK;
  691. #ifdef MSDOS
  692.    if (nonest) filemask = FA_SYSTEM+FA_HIDDEN+FA_RDONLY+FA_ARCH;
  693. #endif
  694.    if (
  695. #ifdef MSDOS
  696.        !k_flag &&
  697. #endif
  698.                   !tapename) tapename = getenv("TAPE");
  699.    if (!a_flag && !x_flag && !t_flag && !d_flag) {
  700.       (void)fprintf(stderr, "Tar: nothing to do\n"); return ERRARG;
  701.    }
  702.    if (a_flag || d_flag) {
  703.       if (i >= argc) {
  704.          (void)fprintf(stderr, "Tar: no files specified\n");
  705.          return ERRARG;
  706.       }
  707. #ifndef USE_COMPRESS
  708.       if (pktype == PKfLZW || pktype == PKpLZW) {
  709.          (void)fprintf(stderr,
  710.          "Tar: this restricted version does not support LZW compression\n");
  711.          return ERRARG;
  712.       }
  713. #endif
  714.    }
  715. #ifdef MSDOS
  716.    if (a_flag && pwd(startdir = salloc(PATHSIZE))) {
  717.       (void)fprintf(stderr, "Tar: can\'t determine current dir\n");
  718.       return ERINIT;
  719.    }
  720. #endif
  721.    if ((k = initape(tapename)) != CORRECT) done(k);
  722.    if ((io_buf=getbuf(cblock ? cblock*BLKSIZE : MAXBLOCK*BLKSIZE)) == NULL)
  723.       done(ESMALL);
  724.    io_2nd = io_buf;
  725.    if (pktype != PKNONE) {
  726.       if (pkalloc()) {/* Memory lack */
  727.          if (!w_flag) {
  728.             outmem(stderr);
  729.          } else {
  730.             (void)fprintf(stderr,
  731.                "No memory for [de]compression. Continue? ");
  732.             k = YES_NO();
  733.             (void)fprintf(stderr, "\n");
  734.             if (!k) done(ESMALL);
  735.             pktype = PKNONE;
  736.          }
  737.       }
  738.    }
  739.    cbreak = FALSE;
  740.  
  741.    if ((k = runtape()) != CORRECT) done(k);
  742. #ifdef UNIX
  743.    myinp = stdin;
  744.    if (!isatty(/* stdin */ 0) && (myinp = fopen("/dev/tty", "r")) == NULL) {
  745.       (void)fprintf(myout,
  746.          "Tar: warning: can\'t open terminal device, may be problems\n");
  747.       myinp = stdin;
  748.    }
  749. #endif
  750.  
  751. #ifdef MSDOS
  752.    if (a_flag && isfile) {
  753.       register char *p;
  754.       lcwdent_t e; char tmpdir[PATHSIZE];
  755.       int flag=0, curdisk = dosgetdisk();
  756.       register d = hasdrive(tapename);
  757.  
  758.       p = d ? (--d, tapename+2) : (d=curdisk, tapename);
  759.       for (k=strlen(p); k && p[k-1]!='\\' && p[k-1]!='/';) --k;
  760.       tmpdir[0] = '\0';
  761.       if (k) { /* archive is not in current dir on either drive */
  762.          register c;
  763.          if (d != curdisk) (void)getfulldir(d, tmpdir);
  764.          c = *(p += k); *p = '\0'; /* cut off the file name */
  765.          if (0 != (flag = cwd(tapename))) {
  766.             (void)fprintf(myout, "Tar: warning: can\'t chdir to %s\n",
  767.                tapename);
  768.          }
  769.          *p = c; /* restore the name */
  770.       } else {
  771.          p = tapename; /* name without directory, may be with drive */
  772.       }
  773.       sa.st_dev = sa.st_ino = -1;
  774.       if (!flag) {
  775.          if (lfindfirst(&e, p, FA_ARCH)) {
  776.             (void)fprintf(myout,
  777.                "Tar: warning: can\'t get stat for %s\n", tapename);
  778.          } else {
  779.             fcb2stat(&sa, e.unopened_fcbP);
  780.             p = e.filenameP;
  781.          }
  782.       }
  783.       archname = salloc(strlen(p)+PATHSIZE);
  784.       if (getfulldir(d, archname)) {
  785.          free(archname);
  786.          archname = NULL;
  787.          k = 0;
  788.       } else {
  789.          archname[k = strlen(archname)] = '\\';
  790.          (void)strcpy(archname+k+1, p);
  791.       }
  792.       if (tmpdir[0] && chdir(tmpdir))
  793.          (void)fprintf(myout,"Tar: warning: can\'t return to %s\n",
  794.             tmpdir);
  795.       if ((!k || strncmp(archname, startdir, k)) && cwd(startdir))
  796.          (void)fprintf(myout,"Tar: warning: can\'t return to %s\n",
  797.             startdir);
  798.    }
  799.    tzset(); /* required for DOS/UNIX time conversion */
  800. #endif
  801.    argc -= i; argv += i;
  802.  
  803.    if (d_flag) {
  804.       register header *h; register long l; register m;
  805.  
  806.       if (d_flag && !isfile) {
  807.          (void)fprintf(stderr,
  808.                        "Tar: delete option is for file archives only\n");
  809.          return ERRARG;
  810.       }
  811.       duptape(tapename);
  812.  
  813.       m = FALSE;
  814.       do {
  815.          if ((k = gethead()) == ERROR) done(ERREAD);
  816.          if (!k) continue;
  817.  
  818.          if (a_flag) {
  819.             long mtm;
  820.  
  821.              if (inargs(argc, argv, hblock->m.name)) {
  822.                 if (u_flag) uplist();
  823.                 if ((mtm = mtime(hblock->m.name)) == -1L) {
  824.                    if (v_flag) {
  825.                       (void)fprintf(myout, "Tar: can\'t access \'%s\'\n",
  826.                                             hblock->m.name);
  827.                    }
  828.                 } else if (!u_flag || mtm > st.st_mtime) {
  829.                    delfile(); continue;
  830.                 }
  831.              }
  832.          } else {/* pure delete */
  833.             if (inargs(argc, argv, hblock->m.name) ||
  834.                ((hblock->m.filetype==TF_LNK || hblock->m.filetype==TF_SYM) &&
  835.                 inargs(argc, argv, hblock->m.linkname))) {
  836.                m = TRUE; delfile(); continue;
  837.             }
  838.          }
  839.  
  840.          /* move file to output archive */
  841.          for (h=steptape(), i=0; i<BLKSIZE/sizeof(int); i++) {
  842.             ((int *)h)[i] = ((int *)hblock)[i];
  843.          }
  844.          if (usize()) {
  845.             l = (st.st_size + (BLKSIZE-1)) / BLKSIZE;
  846.             while (l-- > 0) {
  847.                if ((hblock = readtape()) == NULL) done(ERREAD);
  848.                for (h=steptape(), i=0; i<BLKSIZE/sizeof(int); i++) {
  849.                   ((int *)h)[i] = ((int *)hblock)[i];
  850.                }
  851.             }
  852.          }
  853.       } while (k);
  854.  
  855.       if (a_flag) {
  856.          l = lseek(hwrite, 0L, 1);
  857.          putfiles(argc, argv);
  858.          m = lseek(hwrite, 0L, 1) > l;
  859.       }
  860.  
  861.       if (m) {/* archive was modified */
  862.          endtape();
  863.          if (unlink(tapename)) {
  864.             (void)fprintf(myout, "Tar: can\'t delete \'%s\'\n", tapename);
  865.             done(EWRITE);
  866.          }
  867. #ifdef UNIX
  868.          if (link(scratch, tapename)) {
  869.             (void)fprintf(myout,
  870.                "Tar: can\'t link \'%s\' - data stay in \'%s\'\n",
  871.                tapename, scratch);
  872.             done(EWRITE);
  873.          }
  874.          if (unlink(scratch)) {
  875.             (void)fprintf(myout, "Tar: can\'t delete scratch file\n");
  876.          }
  877. #endif
  878.  
  879. #ifdef MSDOS
  880.          if (rename(scratch, tapename)) {
  881.             (void)fprintf(myout, "Tar: can\'t rename \'%s\' to \'%s\'\n",
  882.                                   scratch, tapename);
  883.             done(EWRITE);
  884.          }
  885. #endif
  886.  
  887. #ifdef UNIX
  888.          if (a_flag && l_flag) {
  889.             register node *this;
  890.  
  891.             for (this=linkhead; this; this=this->next) {
  892.                (void)fprintf(myout, "Tar: missed %d link(s) to \'%s\'\n",
  893.                              this->info.data.count, this->name);
  894.             }
  895.          }
  896. #endif
  897.       } else {
  898.          if (v_flag) (void)fprintf(myout, "Tar: archive unchanged\n");
  899.          (void)close(hwrite);
  900.          if (unlink(scratch)) {
  901.             (void)fprintf(myout, "Tar: can\'t delete scratch file\n");
  902.             done(EWRITE);
  903.          }
  904.       }
  905.    } else if (a_flag) {
  906. #ifdef MSDOS
  907.       if (w_flag && c_flag && devtype == DEV_FLOP) {
  908.          fprintf(stderr,
  909.                  "\007Data on drive %c: would be destroyed. Continue ? ",
  910.                  ndrive + 'A');
  911.          if (!YES_NO()) done(ERRARG);
  912.       }
  913. #endif
  914.       if (a_flag && !c_flag) {
  915.          scantape(argc, argv, acctime); backtape();
  916.       }
  917.       set_sig();
  918.       putfiles(argc, argv);
  919.       endtape();
  920. #ifdef UNIX
  921.       if (l_flag) {
  922.          register node *this;
  923.  
  924.          for (this=linkhead; this; this=this->next) {
  925.             (void)fprintf(myout, "Tar: missed %d link(s) to \'%s\'\n",
  926.                           this->info.data.count, this->name);
  927.          }
  928.       }
  929. #endif
  930.    } else if (x_flag) {
  931. #ifdef UNIX
  932.       (void)umask(0);
  933. #endif
  934.       scantape(argc, argv, extract);
  935.    } else {/* if (t_flag) */
  936.       allbytes = 0; allfiles = 0;
  937.       scantape(argc, argv, catalog);
  938.       if (v_flag) {
  939.          (void)fprintf(myout,
  940.             "\tTotal %u file(s) for %lu bytes in %lu tape blocks\n",
  941.             allfiles, allbytes, allblock);
  942.       }
  943.    }
  944.    _done(); return 0;
  945. }
  946.